//
//  DBNetworkLogDataBase.m
//  AFNetworking
//
//  Created by HaiOu on 2019/11/5.
//

#import "DBNetworkLogDataBase.h"
#import <fmdb/FMDatabaseQueue.h>
#import <fmdb/FMDB.h>

@interface DBNetworkLogDataBase ()
@property (nonatomic, strong) FMDatabaseQueue *queue;
@end

@implementation DBNetworkLogDataBase

+ (instancetype)sharedManager {
    static DBNetworkLogDataBase *sharedManager=nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedManager=[[DBNetworkLogDataBase alloc]init];
        
    });
    return sharedManager;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"NetworkLog"];
        
        NSFileManager *fileManager   = [NSFileManager defaultManager];
        
        if (![fileManager fileExistsAtPath:fileName]) {
            NSError *error;
            if (![fileManager createDirectoryAtPath:fileName withIntermediateDirectories:FALSE attributes:nil error:&error]) {
                NSLog(@"Error creating %@: %@", fileName, error);
            }
        }
        
        NSString *databasePath = [[fileName stringByAppendingPathComponent:@"NetworkLog"] stringByAppendingPathExtension:@"db"];
    
        _queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
        
        [_queue inDatabase:^(FMDatabase *db) {
            // 创建表
            NSString *sql = @"CREATE TABLE IF NOT EXISTS NetworkLog (timestamp TIMESTAMP, uri TEXT, method TEXT, header TEXT, parameters TEXT, code INTEGER, responseObject TEXT, errorDescription TEXT)";
            [db executeUpdate:sql];
        }];
        NSAssert(_queue != nil, @"db error when create queue using path");
    }
    return self;
}

+ (BOOL)insertNetworkLog:(DBNetworkLogModel *)model {
    NSArray<DBNetworkLogModel *> *allDatas = [self queryAllNetworkLog];
    [allDatas enumerateObjectsUsingBlock:^(DBNetworkLogModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (idx >= 99) {
            [self deleteLogWith:obj.date];
        }
    }];
    __block BOOL success = YES;
    [[DBNetworkLogDataBase sharedManager].queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        NSString *sql = @"insert into NetworkLog (timestamp, uri, method, header, parameters, code, responseObject, errorDescription) values (?, ?, ?, ?, ?, ?, ?, ?)";
        BOOL result = [db executeUpdate:sql,
                       [NSDate date],
                       model.uriString,
                       model.method,
                       [self objectToString:model.header],
                       [self objectToString:model.parameters],
                       [NSNumber numberWithInteger:model.code],
                       [self objectToString:model.responseObject],
                       model.errorDescription
                       ];
        success = result;
        if (result == NO) {
            *rollback = YES;
        }
    }];
    return success;
}

+ (NSArray<DBNetworkLogModel *> *)queryAllNetworkLog {
    NSMutableArray <DBNetworkLogModel *> *arrmAlls = [NSMutableArray array];
    [[DBNetworkLogDataBase sharedManager].queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        NSString *sql = @"select * from NetworkLog order by timestamp desc";
        FMResultSet *resultSet = [db executeQuery:sql];
        while ([resultSet next]) {
            DBNetworkLogModel *model = [[DBNetworkLogModel alloc] init];
            model.date = [resultSet dateForColumn:@"timestamp"];
            model.uriString = [resultSet stringForColumn:@"uri"];
            model.method = [resultSet stringForColumn:@"method"];
            model.header = (NSDictionary *)[self jsonStringToObject:[resultSet stringForColumn:@"header"]];
            model.parameters = [self jsonStringToObject:[resultSet stringForColumn:@"parameters"]];
            model.code = [resultSet longLongIntForColumn:@"code"];
            model.responseObject = [self jsonStringToObject:[resultSet stringForColumn:@"responseObject"]];
            model.errorDescription = [resultSet stringForColumn:@"errorDescription"];
            [arrmAlls addObject:model];
        }
    }];
    return arrmAlls;
}

+ (BOOL)deleteLogWith:(NSDate *)date {
    __block BOOL success = YES;
    [[DBNetworkLogDataBase sharedManager].queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        NSString *sql = @"DELETE FROM NetworkLog where timestamp = ?";
        BOOL result = [db executeUpdate:sql, date];
        success = result;
        if (result == NO) {
            *rollback = YES;
        }
    }];
    return success;
}

+ (BOOL)deleteAllNetworkLog {
    __block BOOL success = YES;
    [[DBNetworkLogDataBase sharedManager].queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        NSString *sql = @"delete from NetworkLog";
        BOOL result = [db executeUpdate:sql];
        success = result;
        if (result == NO) {
            *rollback = YES;
        }
    }];
    return success;
}

+ (nullable NSString *)objectToString:(id)obj {
    if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[obj class]]) {
        NSError *parseError = nil;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:&parseError];
        return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    } else {
        return nil;
    }
}

+ (nullable id)jsonStringToObject:(NSString *)jsonString {
    if (jsonString == nil) {
        return nil;
    }
    
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData
                                             options:NSJSONReadingMutableContainers
                                               error:&err];
    if(err) {
        NSLog(@"json解析失败：%@",err);
        return nil;
    }
    if ([jsonObject isKindOfClass:[NSArray class]]) return jsonObject;
    if ([jsonObject isKindOfClass:[NSDictionary class]]) return jsonObject;
    return nil;
}

@end

@implementation DBNetworkLogModel

@end
